#ifndef __V3_H__
#define __V3_H__

#include <string>
using namespace std;

#include <dalelib/maths/mathsstuff.h>
#include <dalelib/maths/v2.h>
#include <dalelib/maths/v4.h>

namespace dalelib
{

class v2;
class v4;

class v3
{
private:

	float f[3];

public:

	/*** constructors ***/
	v3();
	v3(const float _Value);
	v3(const float _Value0, const float _Value1, const float _Value2);
	static const v3 zero;
	static const v3 one;
	static const v3 randCube();
	static const v3 randSphere();

	/*** accessors ***/
	const v3 operator =(const v3& _Value);
	float& x() { return f[0]; }
	float& y() { return f[1]; }
	float& z() { return f[2]; }
	float& operator[](const int _Index) { return f[_Index]; }
	float* ptr() { return &f[0]; }
	const float& x() const { return f[0]; }
	const float& y() const { return f[1]; }
	const float& z() const { return f[2]; }
	const float& operator[](const int _Index) const { return f[_Index]; }
	const float* ptr() const { return &f[0]; }

	/*** unary operation ***/
	v3 operator-() const;

	/*** scalar operations ***/
	void operator+=(const float _Value);
	void operator-=(const float _Value);
	void operator*=(const float _Value);
	void operator/=(const float _Value);

	v3 operator+(const float _Value) const;
	v3 operator-(const float _Value) const;
	v3 operator*(const float _Value) const;
	v3 operator/(const float _Value) const;

	/*** vector operations ***/
	void operator+=(const v3& _Value);
	void operator-=(const v3& _Value);
	void operator*=(const v3& _Value);
	void operator/=(const v3& _Value);

	v3 operator+(const v3& _Value) const;
	v3 operator-(const v3& _Value) const;
	v3 operator*(const v3& _Value) const;
	v3 operator/(const v3& _Value) const;

	float len() const;
	float len2() const;
	v3 unit() const;
	float normalise();
	v3 canonicalise();
	v3 recip() const;
	void clamp(const v3& _Min,const v3& _Max);

	static v3 min(const v3& _V1,const v3& _V2) { return v3(mymin(_V1[0],_V2[0]),mymin(_V1[1],_V2[1]),mymin(_V1[2],_V2[2])); }
	static v3 max(const v3& _V1,const v3& _V2) { return v3(mymax(_V1[0],_V2[0]),mymax(_V1[1],_V2[1]),mymax(_V1[2],_V2[2])); }

	static float dot(const v3 _Value1,const v3 _Value2) { return _Value1[0]*_Value2[0] + _Value1[1]*_Value2[1] + _Value1[2]*_Value2[2]; }
	static v3 cross(const v3 _Value1,const v3 _Value2) { return v3( _Value1[1]*_Value2[2] - _Value1[2]*_Value2[1], _Value1[2]*_Value2[0] - _Value1[0]*_Value2[2], _Value1[0]*_Value2[1] - _Value1[1]*_Value2[0] ); }

//	v3 saturate() const;
	void print(string _String="") const;
	void print(string _String="");

	/*** swizzling ***/
	v2 xy() const;
	v2 xz() const;
	v2 yx() const;
	v2 zx() const;
	v2 yz() const;
	v2 zy() const;

	v3 xxx() const;
	v3 yyy() const;
	v3 zzz() const;

	v4 xyz0() const;
	v4 xyz1() const;

};


} // namespace dalelib

#endif
